package com.example.aiagent.app;


import com.alibaba.cloud.ai.dashscope.api.DashScopeApi;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel;
import com.example.aiagent.advisor.MyLoggerAdvisor;
import com.example.aiagent.advisor.ReReadingAdvisor;
import com.example.aiagent.chatmemory.FileBasedChatMemory;
import com.example.aiagent.tools.ToolRegistration;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.QuestionAnswerAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.InMemoryChatMemory;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.FunctionPromptTemplate;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;

import java.util.List;

import static com.alibaba.nacos.client.aliyun.sample.KmsV3Sample.content;
import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY;
import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY;

@Slf4j
@Component
public class WorkApp {

    private ChatClient chatClient;

    @Resource
    private ToolCallback[] allTools;

    @Resource
    private VectorStore RagVectorStore;

    private static final String SYSTEM_PROMPT =
            "**身份与核心使命：** 您是诺基亚企业专属的智能知识引擎与数字人助手。您的核心使命是深度处理企业知识资产，为全球员工提供即时、精准的知识服务，显著提升工作效率、优化决策流程、强化知识传承，最终赋能诺基亚在通信科技领域的持续创新与市场竞争力。\n" +

                    "**核心能力声明：**\n" +
                    "1.  **智能文档处理专家：** 精通解析多种办公文档格式（Word, PPT, Excel, PDF, TXT, Email），从中精准提取、结构化并索引关键信息（技术参数、项目报告、流程规范、会议纪要、市场分析等）。\n" +
                    "2.  **全面知识库构建者：** 基于处理的海量文档，动态构建、更新和维护覆盖诺基亚产品技术、研发流程、项目管理、市场策略、公司政策、历史案例等维度的统一企业知识图谱。\n" +
                    "3.  **精准智能问答引擎：** 基于构建的知识库，理解员工复杂、专业的自然语言查询（中英文），提供最相关、最准确、来源清晰的答案，支持多轮追问与上下文关联。\n" +
                    "4.  **高效信息导航员：** 不仅能回答问题，更能主动引导用户发现相关文档、知识点或负责人（如有权限信息），减少信息搜寻成本。\n" +

                    "**服务引导与用户交互：**\n" +
                    "1.  **开场引导：** 清晰表明身份（'诺基亚知识助手为您服务'），并简述核心能力（'我能帮您快速查找技术文档、解答产品疑问、理解流程规范、追溯项目历史。请告诉我您的需求'）。\n" +
                    "2.  **需求分类与深度挖掘：** 根据用户初始提问或场景，主动引导用户明确需求细节，以便提供最精准支持：\n" +
                    "    *   **技术/产品查询 (如：5G基站参数、路由器配置指南)：** 询问具体产品型号、软件版本、技术标准、遇到的具体问题或错误代码。\n" +
                    "    *   **流程/规范咨询 (如：项目立项流程、报销政策、安全守则)：** 询问涉及的具体流程环节、政策名称/编号、适用地域/部门、具体疑问点。\n" +
                    "    *   **历史信息/案例检索 (如：某项目经验总结、特定故障的解决方案)：** 询问项目名称/编号、时间范围、关键词、案例类型（成功/失败/风险）。\n" +
                    "    *   **文档定位 (如：寻找某次会议纪要、某份技术白皮书)：** 询问文档标题关键词、作者/部门、大致时间、文档类型。\n" +
                    "    *   **概念/术语解释 (如：解释'网络切片'、'SDN/NFV')：** 询问术语出现的具体上下文或需要了解的深度（基础概念/技术细节/应用场景）。\n" +
                    "3.  **引导详述：** 始终鼓励用户尽可能提供：\n" +
                    "    *   问题/需求的**具体背景**。\n" +
                    "    *   已查阅过哪些相关文档或信息（若有）。\n" +
                    "    *   需要答案达到的**详细程度**（概览/步骤/原理/示例）。\n" +
                    "    *   涉及的关键**名称/编号/代码**（产品、项目、文档、流程、错误码等）。\n" +

                    "**输出规范与价值强调：**\n" +
                    "1.  **答案精准与溯源：** 提供的答案必须严格基于诺基亚内部权威知识库，并清晰标注信息来源（文档标题、章节、链接等，如有）。无法确认时，明确告知并建议咨询渠道。\n" +
                    "2.  **结构化与清晰：** 答案组织逻辑清晰，重点突出。复杂问题分点阐述，必要时使用表格、代码块等增强可读性。技术术语提供简明解释。\n" +
                    "3.  **效率导向：** 回答力求简洁直接，直击要点，避免冗长无关信息。提供进一步探索的路径（如相关文档链接、知识点）。\n" +
                    "4.  **安全与合规：** 严格遵守诺基亚数据安全与保密政策。不处理、不透露任何敏感信息。提醒用户勿输入机密内容。\n" +
                    "5.  **价值重申：** 在交互中适时体现核心价值：'这能帮您节省查阅时间'、'此信息来自最新版规范'、'相关案例可参考XXX'、'这将有助于项目决策效率'。\n" +

                    "**终极目标：** 成为诺基亚员工不可或缺的智慧伙伴，通过无缝的知识获取与共享，加速问题解决，激发创新潜能，提升个人与组织效能，巩固诺基亚在激烈市场竞争中的技术领导力和运营卓越性。";


    /**
     * 初始化ChatClient配置
     * @param ollamaChatModel
     */
    public WorkApp(ChatModel ollamaChatModel) {
        // 基于文件存储的对话记忆
        String fileDir = System.getProperty("user.dir") + "/chat-memory";
        ChatMemory chatMemory = new FileBasedChatMemory(fileDir);
        // 初始化基于内存的对话记忆
//        ChatMemory chatMemory = new InMemoryChatMemory();
        chatClient = ChatClient.builder(ollamaChatModel)
                .defaultAdvisors(
                        new MessageChatMemoryAdvisor(chatMemory),
                        //自定义日志advisor
                        new MyLoggerAdvisor()
//                        new ReReadingAdvisor()
                )
                .defaultSystem(SYSTEM_PROMPT)
                .build();

        // 存到数据库中
    }

    record WorkReport(String title, List<String> suggestions) {

    }

    /**
     * AI 基础对话（支持多轮对话记忆）
     * @param message
     * @param chatId
     * @return
     */
    public String doChat(String message, Long chatId) {
        ChatResponse chatResponse = chatClient.prompt()
                .user(message)
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 5))
                .call()
                .chatResponse();

        String content = chatResponse.getResult().getOutput().getText();
        log.info("content:{}", content);
        return content;
    }

    /**
     * AI 报告功能（支持结构化输出）
     * @param message
     * @param chatId
     * @return
     */
    public WorkReport doChatWithReport(String message, String chatId) {
        WorkReport loveReport = chatClient.prompt()
                .user(message)
//                .system(SYSTEM_PROMPT + "每次对话后都要生成结果，标题为{用户名}的报告，内容为建议列表")
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 5))
                .call()
                .entity(WorkReport.class);

        log.info("loveReport:{}", loveReport);
        return loveReport;
    }

    /**
     * AI 基础对话（支持多轮对话记忆）,SSE输出
     * @param message
     * @param chatId
     * @return
     */
    public Flux<String> doChatWithStream(String message, Long chatId) {
        return chatClient.prompt()
                .user(message)
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 5))
                .advisors(new QuestionAnswerAdvisor(RagVectorStore))
                .stream()
                .content();
    }

    public void deleteChat(Long chatId) {
        String fileDir = System.getProperty("user.dir") + "/chat-memory";
        ChatMemory chatMemory = new FileBasedChatMemory(fileDir);
        chatMemory.clear(chatId.toString());
    }

    /**
     * AI调用工具处理文档
     * @param message
     * @param chatId
     */
    public Flux<String> doWithDoc(String message, Long chatId,String fileName) {
        return chatClient
                .prompt()
                .user(message + ", " + fileName)
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 5))
                // 开启日志，便于观察效果
                .advisors(new MyLoggerAdvisor())
                .advisors(new QuestionAnswerAdvisor(RagVectorStore))
                .tools(allTools)
                .stream()
                .content();
    }

    public String doChatWithRag(String message, String chatId) {
        ChatResponse chatResponse = chatClient.prompt()
                .user(message)
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 5))
                // 开启日志，便于观察效果
                .advisors(new MyLoggerAdvisor())
                // 应用RAG知识库回答问题
                .advisors(new QuestionAnswerAdvisor(RagVectorStore))
                .tools(allTools)
                .call()
                .chatResponse();
        String content = chatResponse.getResult().getOutput().getText();
        log.info("content:{}", content);
        return content;
    }
}

